home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_01_07 / 1n07066a < prev    next >
Text File  |  1990-09-10  |  5KB  |  163 lines

  1. /*
  2. **  Figure 3 - Gameport support functions
  3. **
  4. **  This file contains several related functions required to access the
  5. **  switch inputs on the gameport in a controlled, debounced fashion.
  6. **
  7. **  In order to work correctly, the routine "debounce()" MUST be called
  8. **  often as a part of the user program.  Debouncing takes place as a
  9. **  function of the time interval between successive calls to debounce().
  10. **
  11. **  It does not use a specific timebase, although the debounce() function
  12. **  could be tied to the user timebase, Int 1Ch.
  13. */
  14.  
  15. #include <stdio.h>
  16.  
  17. #define GAMEPORT 0x201        /* gameport address */
  18. #define IDLE 0                /* state definitions for debouncer */
  19. #define INPROG 1
  20. #define WAITOPEN 2
  21.  
  22. void            init_game(int),
  23.                 clear_game(void),
  24.                 debounce(void);
  25.  
  26. unsigned char   get_press(void);
  27.  
  28. struct {
  29.     unsigned char seed;
  30.     unsigned char counter;
  31.     unsigned char new_value;
  32.     unsigned char last_value;
  33.     unsigned char state;
  34.     unsigned char key_down;
  35.     int multi;
  36.     } gamesw;
  37.  
  38.  
  39. /*
  40. ** init_game(mode)
  41. ** call this routine before using any of the gameport support routines.
  42. ** Or, manually initialize the gamesw structure.
  43. ** "mode" is 1 to allow multiple keypresses, 0 for exclusion
  44. */
  45.  
  46. void init_game(int mode)
  47. {
  48.         gamesw.seed = 100;
  49.         gamesw.multi = (unsigned char)(mode & 0xff);
  50.         clear_game();
  51. }
  52.  
  53.  
  54. /*
  55. ** clear_game()
  56. **     clears the game port structure items and allows for immediate
  57. **     re-processing of new keystrokes.
  58. */
  59.  
  60. void clear_game(void)
  61. {
  62.         gamesw.key_down = gamesw.last_value = gamesw.new_value = 0;
  63.         gamesw.state = IDLE;
  64. }
  65.  
  66.  
  67. /*
  68. ** get_press()
  69. **    returns a fully debounced key value, or NUL if nothing
  70. **    pressed.  Note that getting a waiting keystroke will re-init
  71. **    the control structure.
  72. */
  73.  
  74. unsigned char get_press(void)
  75. {
  76.         unsigned char i;
  77.  
  78.         if (gamesw.key_down == 0)
  79.                 return(0);
  80.         i = gamesw.key_down;
  81.         gamesw.key_down = 0;
  82.         return(i);
  83. }
  84.  
  85.  
  86. /*
  87. ** debounce()
  88. **
  89. ** This routine is called periodically (try for about 20 to 200 times per
  90. ** second, nominal) to process potential key presses.  This system
  91. ** does NOT allow multiple key presses if the gamesw.multi byte is set
  92. ** to FALSE, and under those conditions will wait for a key to be
  93. ** fully debounced in order to return a value.
  94. ** If gamesw.multi is TRUE, then any stable value will be returned.
  95. ** In all cases, a pending keyvalue MUST be fetched via get_press or
  96. ** cleared via clear_game() before any further keypress is recognized.
  97. ** This routine returns nothing except through the gamesw structure.
  98. */
  99.  
  100. void debounce(void)
  101. {
  102.         unsigned char i;
  103.  
  104.         if (gamesw.key_down != 0)
  105.                 return;         /* do nothing until a key is read       */
  106.  
  107.         i = inp(GAMEPORT);      /* read port, raw                       */
  108.  
  109.         /* convert bits to high active, in lower nibble                 */
  110.  
  111.         i = ~i;
  112.         i >>= 4;
  113.         gamesw.new_value = i & 0x0f;
  114.         switch (gamesw.new_value)
  115.         {
  116.         case 1:  
  117.         case 2:  
  118.         case 4:  
  119.         case 8:  
  120.         case 0:
  121.                 break;
  122.         default:                /* multiple keys down                   */
  123.                 if (gamesw.multi)
  124.                         break;  /* multiple keys allowed                */
  125.                 gamesw.state = WAITOPEN; /* else wait for all open      */
  126.                 return;
  127.         }
  128.         if (gamesw.new_value != gamesw.last_value)
  129.                 gamesw.state = IDLE;
  130.         switch (gamesw.state)
  131.         {
  132.         case IDLE:
  133.                 if (gamesw.new_value == 0)
  134.                         break;
  135.  
  136.                 /* save original keystroke */
  137.  
  138.                 gamesw.last_value = gamesw.new_value;
  139.                 gamesw.counter = gamesw.seed;
  140.                 gamesw.state = INPROG;
  141.                 break;
  142.         case INPROG:
  143.                 if (--gamesw.counter > 0)
  144.                         break;                  /* not timed out yet    */
  145.                 gamesw.state = WAITOPEN;
  146.                 gamesw.key_down = gamesw.new_value;
  147.                 break;
  148.         case WAITOPEN:
  149.                 if (gamesw.new_value != 0)
  150.                 {       /* any closure restarts timeout                 */
  151.                         gamesw.counter = gamesw.seed;
  152.                         break;
  153.                 }
  154.                 if (--gamesw.counter > 0)
  155.                         break;
  156.                 gamesw.state = IDLE;
  157.                 gamesw.last_value = gamesw.new_value = 0;
  158.                 break;
  159.         default:
  160.                 break;
  161.         }
  162. }
  163.